using System.Text.RegularExpressions;
using MultiAgentsClient.Service.WorkflowEngine.BuiltInNodes;
using MultiAgentsClient.Shared;
using MultiAgentsServer.Scripts.Shared.WorkflowEngine.BuiltInNodes;
using Newtonsoft.Json;

namespace MultiAgentsClient.Service.WorkflowEngine.BaseNodes;


/// <summary>
/// Allowed Variable types: int, float, string
/// Using custom converter, no JSONIgnore needed
/// </summary>
public abstract class BaseNode : IBehaviorTreeNode
{
    [NodeInstanceSerialize] public string Id { get; set; } = "";
    [NodeInstanceSerialize] public string CustomName = "SomeCustomName";
    [NodeInstanceSerialize] public float nodePosX;
    [NodeInstanceSerialize] public float nodePosY;

    protected BehaviorTreeContext runtimeContext;

    [JsonConstructor]
    public BaseNode()
    {
        CustomName = GetType().Name;
    }

    public abstract void Dispose();


    #region RuntimeOnly
    /// <summary>
    /// Called in WorkflowSession to setup node for runtime
    /// </summary>
    /// <param name="workflowContext"></param>
    public virtual void InitNodeForRuntime(BehaviorTreeContext workflowContext)
    {
        runtimeContext = workflowContext;
    }

    /// <summary>
    /// Called externally to run node
    /// </summary>
    /// <returns></returns>
    public abstract Task<NodeOutcome> ExecuteNodeAsync();

    protected TVar InsertVariable<TVar>(TVar rawString)
    {
        var deepCopyReturn = JsonConvert.DeserializeObject<TVar>(JsonConvert.SerializeObject(rawString));

        switch (deepCopyReturn)
        {
            case List<IfElseNode.Condition> conditions:
                {
                    foreach (var condition in conditions)
                    {
                        condition.Value = InsertVariable(condition.Value);
                        condition.Variable = InsertVariable(condition.Variable);
                    }
                    return (TVar)(object)conditions;
                }

            case string inputStr:
                {
                    Regex regex = new("{{#(.*?)#}}");
                    MatchCollection matches = regex.Matches(inputStr);

                    foreach (Match match in matches)
                    {
                        var variableName = match.Groups[1].Value;

                        if (runtimeContext.HasVar<string>(variableName))
                        {
                            inputStr = inputStr.Replace(match.Value, $"{runtimeContext.GetVar<string>(variableName)}");
                        }
                    }

                    return (TVar)(object)inputStr;
                }

            case List<string> listOfStr:
                {
                    for (int i = 0; i < listOfStr.Count; i++)
                    {
                        listOfStr[i] = InsertVariable(listOfStr[i]);
                    }
                    return (TVar)(object)listOfStr;
                }

            case List<LlmMessageSimp> llmMsgs:
                {
                    for (var i = 0; i < llmMsgs.Count; i++)
                    {
                        llmMsgs[i].Message = InsertVariable(llmMsgs[i].Message);
                    }
                    return (TVar)(object)llmMsgs;
                }
            case List<ToolCallParams> toolCallParams:
                {
                    for (var i = 0; i < toolCallParams.Count; i++)
                    {
                        toolCallParams[i].value = InsertVariable(toolCallParams[i].value);
                    }
                    return (TVar)(object)toolCallParams;
                }
            case ListVariable<string> listOfStrVar:
                {
                    Regex regex = new("{{#(.*?)#}}");
                    MatchCollection matches = regex.Matches(listOfStrVar.variableName);

                    string variableName = "";
                    if (matches.Count > 0)
                    {
                        variableName = matches[0].Groups[1].Value;
                    }

                    if (runtimeContext.HasVar<List<string>>(variableName))
                    {
                        listOfStrVar.listOfStr = runtimeContext.GetVar<List<string>>(variableName);
                    }

                    return (TVar)(object)listOfStrVar;
                }
            default:
                {
                    throw new Exception("damn it");
                }
        }
    }
    #endregion
}
